package com.fight.strive.sys.modules.rbac.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fight.strive.sys.modules.exception.StriveException;
import com.fight.strive.sys.modules.mybatisplus.utils.MyBatisPlusUtils;
import com.fight.strive.sys.modules.rbac.constants.RbacRoleConstants;
import com.fight.strive.sys.modules.rbac.dao.RbacRoleMapper;
import com.fight.strive.sys.modules.rbac.dto.RbacRoleDto;
import com.fight.strive.sys.modules.rbac.entity.RbacRoleEntity;
import com.fight.strive.sys.modules.rbac.service.RbacRoleService;
import com.fight.strive.sys.modules.request.dto.PageRequest;
import com.fight.strive.sys.modules.response.dto.PageData;
import com.fight.strive.sys.modules.sysadmin.utils.SysAdminUtils;
import com.fight.strive.sys.utils.BeanUtils;
import com.fight.strive.sys.utils.CollectionUtils;
import com.fight.strive.sys.utils.ObjectUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.List;

/**
 * @author ZHOUXIANG
 */
@Slf4j
@Service
public class RbacRoleServiceImpl
        extends ServiceImpl<RbacRoleMapper, RbacRoleEntity>
        implements RbacRoleService {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    public void saveRole(@Valid RbacRoleDto rbacRoleDto) {
        RbacRoleEntity rbacRoleEntity = this.getByCodeAndNotId(
                rbacRoleDto.getRoleCode(), rbacRoleDto.getId());
        if (ObjectUtils.notNull(rbacRoleEntity)) {
            throw new StriveException("该角色代码已存在");
        } else {
            rbacRoleEntity = new RbacRoleEntity();
        }
        BeanUtils.copyPropertiesIgnoreNull(rbacRoleDto, rbacRoleEntity);
        this.saveOrUpdate(rbacRoleEntity);
        // 插入缓存
        this.updateRedisData(rbacRoleEntity);
    }

    @Override
    public RbacRoleEntity getByCodeAndNotId(String roleCode, Long id) {
        QueryWrapper<RbacRoleEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("role_code", roleCode);
        if (ObjectUtils.notNull(id)) {
            queryWrapper.ne("id", id);
        }
        return this.getOne(queryWrapper);
    }

    @Override
    public PageData<RbacRoleEntity> getRoleList(
            PageRequest<RbacRoleDto> pageRequest) {
        RbacRoleDto rbacRoleDto = pageRequest.getCondition();
        QueryWrapper<RbacRoleEntity> queryWrapper = new QueryWrapper<>();
        MyBatisPlusUtils.buildQuery(queryWrapper, rbacRoleDto,"roleCode");
        MyBatisPlusUtils.buildSortOrderQuery(queryWrapper, pageRequest.getSort());
        Page<RbacRoleEntity> page = pageRequest.buildMybatisPlusPage();
        IPage<RbacRoleEntity> iPage = this.page(page, queryWrapper);
        return new PageData<>(iPage);
    }

    @Override
    public void deleteRole(RbacRoleDto rbacRoleDto) {
        if (ObjectUtils.isNull(rbacRoleDto.getId())) {
            throw new StriveException("要删除的角色ID为空");
        }
        // 删除缓存
        RbacRoleEntity entity = this.getRoleById(rbacRoleDto.getId());
        this.deleteRedisData(entity);
        // 删除数据库
        this.removeById(entity.getId());
    }

    @Override
    public void deleteBatchRole(List<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            throw new StriveException("要删除的角色ID为空");
        }
        for (Long id : ids) {
            RbacRoleEntity entity = this.getRoleById(id);
            this.deleteRedisData(entity);
        }
        this.removeByIds(ids);
    }

    @Override
    public RbacRoleEntity getRoleById(Long roleId) {
        RbacRoleEntity entity = this.getRedisData(
                RbacRoleConstants.ROLE_ID_KEY, roleId);
        if (ObjectUtils.isNull(entity)) {
            entity = this.getById(roleId);
            if (ObjectUtils.notNull(entity)) {
                this.updateRedisData(entity);
            }
        }
        return entity;
    }

    @Override
    public RbacRoleEntity getRoleByCode(String roleCode) {
        Long tenantId = SysAdminUtils.getCurrentTenantId();
        RbacRoleEntity entity = this.getRedisData(
                RbacRoleConstants.ROLE_CODE_ID_KEY
                        .concat(String.valueOf(tenantId)), roleCode);
        if (ObjectUtils.isNull(entity)) {
            QueryWrapper<RbacRoleEntity> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("role_code", roleCode);
            entity = this.getOne(queryWrapper, false);
            if (ObjectUtils.notNull(entity)) {
                this.updateRedisData(entity);
            }
        }
        return entity;
    }

    @Override
    public void updateRedisData(RbacRoleEntity entity) {
        // roleId -> entity
        redisTemplate.opsForHash().put(
                RbacRoleConstants.ROLE_ID_KEY, entity.getId(), entity);
        // roleCode -> roleId
        redisTemplate.opsForHash().put(
                RbacRoleConstants.ROLE_CODE_ID_KEY
                        .concat(String.valueOf(entity.getTenantId())),
                entity.getRoleCode(), entity.getId());
    }

    @Override
    public RbacRoleEntity getRedisData(String key, Object hashKey) {
        if (RbacRoleConstants.ROLE_ID_KEY.equals(key)) {
            return (RbacRoleEntity) redisTemplate.opsForHash().get(
                    RbacRoleConstants.ROLE_ID_KEY, hashKey);
        } else {
            Long roleId = (Long) redisTemplate.opsForHash().get(key, hashKey);
            if (ObjectUtils.notNull(roleId)) {
                return (RbacRoleEntity) redisTemplate.opsForHash().get(
                        RbacRoleConstants.ROLE_ID_KEY, roleId);
            }
        }
        return null;
    }

    @Override
    public void deleteRedisData(RbacRoleEntity entity) {
        redisTemplate.opsForHash().delete(
                RbacRoleConstants.ROLE_ID_KEY, entity.getId());
    }
}
